package ch.sysventory.builder;

import java.util.ArrayList;

import ch.sysventory.domain.ComputerInformation;
import ch.sysventory.domain.InstalledSoftware;
import ch.sysventory.domain.NIC;
import ch.sysventory.domain.OSInformation;
import ch.sysventory.domain.PrinterInformation;
import ch.sysventory.domain.ProcessorInformation;

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.jacob.com.EnumVariant;
import com.jacob.com.Variant;

/**
 * Java Programm des mittels der Windows WMI WQL (isch fast glich wie SQL) den
 * PC-Auslesen kann
 * 
 * @author Emanuel
 */
public class ScannPC implements ScannPCBuilder {

	// Attribute für die NIC Klasse
	private NIC nic;
	private ArrayList<NIC> nicList;

	// Attribute für die OSInformation Klasse
	private OSInformation osInformation;
	private ArrayList<OSInformation> osInformationList;

	// Attribute für die Installiereten Software Klasse
	private InstalledSoftware installedSoftware;
	private ArrayList<InstalledSoftware> installedSoftwareList;

	// Attribute für die ComputerInformation Klasse
	private ComputerInformation computerInformation;
	private ArrayList<ComputerInformation> computerInformationList;

	// Attribute für die Drucker Informationen Klasse
	private PrinterInformation printerInformation;
	private ArrayList<PrinterInformation> printerInformationList;

	// Attribute für die Prozessor Informationen Klasse
	private ProcessorInformation processorInformation;
	private ArrayList<ProcessorInformation> processorInformationList;

	// Attribute für die ActiveXComponenten
	private String host;
	private String connection;
	private static ActiveXComponent axWMI;

	public ScannPC() {

		nicList = new ArrayList<NIC>();
		osInformationList = new ArrayList<OSInformation>();
		installedSoftwareList = new ArrayList<InstalledSoftware>();
		computerInformationList = new ArrayList<ComputerInformation>();
		printerInformationList = new ArrayList<PrinterInformation>();
		processorInformationList = new ArrayList<ProcessorInformation>();

		this.host = "localhost";
		this.connection = String.format("winmgmts:\\\\%s\\root\\CIMV2", host);
		this.axWMI = new ActiveXComponent(connection);
	}

	public ArrayList<NIC> readNIC() {

		String query = "Select Description, IPAddress, DefaultIPGateway, MACAddress, DHCPServer, IPSubnet from Win32_NetworkAdapterConfiguration where IPEnabled=TRUE";
		Variant vCollection = axWMI.invoke("ExecQuery", new Variant(query));

		// Our result is a collection, so we need to work though the.
		EnumVariant enumVariant = new EnumVariant(vCollection.toDispatch());

		Dispatch item = null;
		while (enumVariant.hasMoreElements()) {

			nic = new NIC();
			item = ((Variant) enumVariant.nextElement()).toDispatch();

			// Dispatch.call returns a Variant which we can convert to a java
			// form.
			nic.setIpAddressV4(splitIPAddress(Dispatch.call(item, "IPAddress")
					.toString(), 4));
			nic.setIpAddressV6(splitIPAddress(Dispatch.call(item, "IPAddress")
					.toString(), 6));

			nic.setSubnet(splitSubnet(Dispatch.call(item, "IPSubnet")
					.toString()));

			nic.setNicDescription(Dispatch.call(item, "Description").toString());
			nic.setStandardGateway(Dispatch.call(item, "DefaultIPGateway")
					.toString());
			nic.setMacAddress(Dispatch.call(item, "MACAddress").toString());
			nic.setDhcp(Dispatch.call(item, "DHCPServer").toString());

			nicList.add(nic);
		}
		return nicList;
	}

	public ArrayList<OSInformation> readOSInformation() {

		String query = "Select Name, OSArchitecture, Version from Win32_OperatingSystem";
		Variant vCollection = axWMI.invoke("ExecQuery", new Variant(query));

		EnumVariant enumVariant = new EnumVariant(vCollection.toDispatch());

		Dispatch item = null;
		while (enumVariant.hasMoreElements()) {

			osInformation = new OSInformation();

			item = ((Variant) enumVariant.nextElement()).toDispatch();
			// Man hat zuerst einen String, und dieser String kann dann direkt
			// abgeschnitten werden, darum muss man den "alten" String zweimal
			// erwähnen
			osInformation
					.setOsName(Dispatch
							.call(item, "Name")
							.toString()
							.substring(
									0,
									Dispatch.call(item, "Name").toString()
											.indexOf('|')));
			osInformation.setOsArchitecture(Dispatch.call(item,
					"OSArchitecture").toString());
			osInformation.setOsVersion(Dispatch.call(item, "Version")
					.toString());

			osInformationList.add(osInformation);
		}
		return osInformationList;
	}

	public ArrayList<ProcessorInformation> readProcessorInformation() {

		String query = "Select Description, Family, NumberOfCores, MaxClockSpeed  from Win32_Processor";
		Variant vCollection = axWMI.invoke("ExecQuery", new Variant(query));

		EnumVariant enumVariant = new EnumVariant(vCollection.toDispatch());

		Dispatch item = null;
		while (enumVariant.hasMoreElements()) {

			processorInformation = new ProcessorInformation();

			item = ((Variant) enumVariant.nextElement()).toDispatch();

			processorInformation.setCpuDescription(Dispatch.call(item,
					"Description").toString());
			processorInformation.setProcessorFamily(Dispatch.call(item,
					"Family").toString());
			processorInformation.setNumberOfCores(Dispatch.call(item,
					"NumberOfCores").toString());
			processorInformation.setClockSpeed(Dispatch.call(item,
					"MaxClockSpeed").toString());

			processorInformationList.add(processorInformation);
		}
		return processorInformationList;
	}

	public ArrayList<PrinterInformation> readPrinterInformation() {

		String queryPrinter = "Select Name, DriverName from Win32_Printer";
		String queryDriver = "Select Version from Win32_PrinterDriver";

		Variant vCollectionPrinter = axWMI.invoke("ExecQuery", new Variant(
				queryPrinter));

		Variant vCollectionDriver = axWMI.invoke("ExecQuery", new Variant(
				queryDriver));

		EnumVariant enumVariantPrinter = new EnumVariant(
				vCollectionPrinter.toDispatch());

		Dispatch item = null;
		while (enumVariantPrinter.hasMoreElements()) {

			printerInformation = new PrinterInformation();

			item = ((Variant) enumVariantPrinter.nextElement()).toDispatch();

			printerInformation.setPrinterName(Dispatch.call(item, "Name")
					.toString());
			printerInformation.setPrinterDriverName(Dispatch.call(item,
					"DriverName").toString());

			printerInformationList.add(printerInformation);
		}

		EnumVariant enumVariantDriver = new EnumVariant(
				vCollectionDriver.toDispatch());
		while (enumVariantDriver.hasMoreElements()) {

			item = ((Variant) enumVariantDriver.nextElement()).toDispatch();

			for (int i = 0; i < printerInformationList.size(); i++) {

				printerInformationList.get(i).setPrinterDriverVersion(
						Dispatch.call(item, "Version").toString());
			}
		}
		return printerInformationList;

	}

	public ArrayList<InstalledSoftware> readInstalledSoftware() {

		String query = "Select Name, Version from Win32_Product";
		Variant vCollection = axWMI.invoke("ExecQuery", new Variant(query));

		EnumVariant enumVariant = new EnumVariant(vCollection.toDispatch());

		Dispatch item = null;
		while (enumVariant.hasMoreElements()) {

			installedSoftware = new InstalledSoftware();

			item = ((Variant) enumVariant.nextElement()).toDispatch();

			installedSoftware.setInstalledSoftwareName(Dispatch.call(item,
					"Name").toString());
			installedSoftware.setInstalledSoftwareVersion(Dispatch.call(item,
					"Version").toString());

			installedSoftwareList.add(installedSoftware);
		}
		return installedSoftwareList;
	}

	public ArrayList<ComputerInformation> readComputerIformation() {

		String query = "Select Name, Model from Win32_ComputerSystem";
		
		String queryRam ="Select Capacity from Win32_PhysicalMemory";
		
		Variant vCollection = axWMI.invoke("ExecQuery", new Variant(query));
		
		Variant vCollectionRam = axWMI.invoke("ExecQuery", new Variant(queryRam));

		EnumVariant enumVariant = new EnumVariant(vCollection.toDispatch());

		Dispatch item = null;
		while (enumVariant.hasMoreElements()) {

			computerInformation = new ComputerInformation();

			item = ((Variant) enumVariant.nextElement()).toDispatch();

			computerInformation.setComputerName(Dispatch.call(item, "Name").toString());
			computerInformation.setComputerModel(Dispatch.call(item, "Model").toString());
			computerInformation.setComputerSID(readSID());

			computerInformationList.add(computerInformation);
		}
		
		EnumVariant enumVariantRam = new EnumVariant(vCollectionRam.toDispatch());
		
		double size = 0;
		
		while (enumVariantRam.hasMoreElements()){
			
			item = ((Variant) enumVariantRam.nextElement()).toDispatch();
			
			String s = Dispatch.call(item, "Capacity").toString();
			
			size +=(Double.parseDouble(s));
		}
		
		double Ram = size / 1073741824;
		computerInformationList.get(0).setInstalledRam(Ram);
		return computerInformationList;
	}

	
	public String splitIPAddress(String name, int version) {

		String[] str;
		String delimiter = "\\s+";

		str = name.split(delimiter);

		if (version == 4) {
			return str[1];
		} else {
			return str[2];
		}
	}

	public String splitSubnet(String name) {

		String[] str;
		String delimiter = "\\s+";

		str = name.split(delimiter);

		return str[1];
	}

	
	public static String readSID() {

		String query = "Select SID from Win32_UserAccount ";
		Variant vCollection = axWMI.invoke("ExecQuery", new Variant(query));

		EnumVariant enumVariant = new EnumVariant(vCollection.toDispatch());

		Dispatch item = null;

		
		item = ((Variant) enumVariant.nextElement()).toDispatch();
		String sidLong = Dispatch.call(item, "SID").toString();

		String sidShort = (sidLong.substring(0, sidLong.length() - 4));

		return sidShort;
	}
}
